
#pragma once
#include <string>
#include <vector>
#include <unordered_map>

#ifdef _WIN32
#include <Windows.h>
#else
#error("this lib in only for windows")
#endif



namespace CXLib::CXSddl {

	struct _AceDesc {
		std::string type_desc;
		std::string flags_desc;
		std::string rights_desc;
		std::string object_guid_desc;
		std::string inherit_object_guid_desc;
		std::string account_sid_desc;
	};
	using AceDesc = struct _AceDesc;

	struct _AceInfo {
		std::string type;
		std::string flags;
		std::string rights;
		std::string object_guid;
		std::string inherit_object_guid;
		std::string account_sid;

		AceDesc desc;
	};
	using AceInfo = struct _AceInfo;

	struct _RightItem {
		std::string abbr;
		std::string right;
		DWORD       value;
	};
	using RightItem = struct _RightItem;

	struct _RZSDDLInfo {
		std::string sddl;
		std::vector<AceInfo> aces;
		bool isAdmin = false;
		bool isEveryone = false;
	};
	using RZSDDLInfo = struct _RZSDDLInfo;

	/// <summary>
	/// To parse the ACE string
	/// </summary>
	/// <param name="ace">e.g. "A;;FA;;;SY"</param>
	/// <returns>AceInfo</returns>
	AceInfo cxParseACE(const std::string& ace);

	/// <summary>
	/// Parse SDDL
	/// </summary>
	/// <param name="sddl">e.g. "D:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;0x1201bf;;;WD)(A;;0x1200a9;;;RC)"</param>
	/// <returns></returns>
	RZSDDLInfo cxParseSDDL(const std::string& sddl);

	/// <summary>
	/// Get SDDL of HID path
	/// </summary>
	/// <param name="PID"></param>
	/// <param name="VID"></param>
	/// <param name="security">Should be DACL_SECURITY_INFORMATION or SACL_SECURITY_INFORMATION</param>
	/// 
	/// <returns>
	///     key: HID path   
	///     value: SDDL 
	/// </returns>
	std::unordered_map<std::string, std::string> cxGetHIDsACL(USHORT PID = 0, USHORT VID = 0, DWORD security = DACL_SECURITY_INFORMATION);

	/// <summary>
	/// Change HID pat's SDDL, only support admin or everyone
	/// </summary>
	/// <param name="devicePath"></param>
	/// <param name="isAdmin"></param>
	/// <param name="errMsg"></param>
	/// <returns></returns>
	bool cxSetDeviceSecurity(LPCSTR devicePath, bool isAdmin, std::string& errMsg);

	/// <summary>
	/// 开启或关闭进程的 SE_SECURITY_NAME 特权。开启后，进程可以读取和修改资源的 SACL（系统访问控制列表），用于审计设置。
	/// </summary>
	/// <param name="hProcess">进程句柄</param>
	/// <param name="enable">是否启用特权</param>
	/// <returns>Win32 错误码，0 表示成功</returns>
	DWORD cxEnableSecurityPrivilege(HANDLE hProcess, bool enable);

	/// <summary>
	/// 设置指定设备路径的 SACL（系统访问控制列表）。
	/// 若 enableSACL 为 true，则为 Everyone 添加审计 ACE。
	/// 若 enableSACL 为 false，则移除 SACL（即不设置任何审计规则）。
	/// 需管理员权限，并临时启用 SE_SECURITY_NAME 特权。
	/// </summary>
	/// <param name="path">设备对象路径，如 "\\?\hid#..."</param>
	/// <param name="enableSACL">是否启用 Everyone 的审计 ACE</param>
	/// <returns>Win32 错误码，ERROR_SUCCESS 表示成功</returns>
	DWORD cxSetSACL(const char* devicePath, bool enableSACL);

	/// <summary>
	/// 使用 SDDL 字符串设置文件 SACL，更直接和可靠的方法
	/// </summary>
	/// <param name="path">文件路径</param>
	/// <param name="enableSACL">是否启用审计</param>
	/// <returns>Win32 错误码</returns>
	DWORD cxSetSACLWithSDDL(const char* path, bool enableSACL);

	/// <summary>
	/// 专门用于设备对象（如 HID 设备）的 SACL 设置函数
	/// 使用 SE_KERNEL_OBJECT 类型和 SetSecurityInfo API
	/// </summary>
	/// <param name="devicePath">设备路径，如 HID 设备路径</param>
	/// <param name="enableSACL">是否启用审计</param>
	/// <returns>Win32 错误码</returns>
	DWORD cxSetDeviceSACL(const char* devicePath, bool enableSACL);

	/// <summary>
	/// 获取指定对象（如文件、设备）的 SACL（系统访问控制列表）字符串（SDDL格式）。
	/// 需管理员权限，并临时启用 SE_SECURITY_NAME 特权，否则无法读取 SACL。
	/// 读取完成后自动关闭特权。
	/// </summary>
	/// <param name="filePath">对象路径，如 "\\?\hid#..." 或文件路径</param>
	/// <param name="sacl">输出参数，返回 SACL 的 SDDL 字符串（如 "S:AI(AU;SA;WD;;;WD)"）</param>
	/// <returns>Win32 错误码，ERROR_SUCCESS 表示成功，其他值表示失败原因</returns>
	DWORD cxGetSACL(const char* filePath, std::string& sacl);
}
